package com.yingxue.lesson.service.impl;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yingxue.lesson.contants.Constant;
import com.yingxue.lesson.entity.SysDept;
import com.yingxue.lesson.entity.SysRole;
import com.yingxue.lesson.entity.SysUser;
import com.yingxue.lesson.exception.BusinessException;
import com.yingxue.lesson.exception.code.BaseResponseCode;
import com.yingxue.lesson.mapper.SysDeptMapper;
import com.yingxue.lesson.mapper.SysRoleMapper;
import com.yingxue.lesson.mapper.SysUserMapper;
import com.yingxue.lesson.mapper.SysUserRoleMapper;
import com.yingxue.lesson.service.*;
import com.yingxue.lesson.utils.JwtTokenUtil;
import com.yingxue.lesson.utils.PageUtil;
import com.yingxue.lesson.utils.PasswordUtils;
import com.yingxue.lesson.utils.TokenSetting;
import com.yingxue.lesson.vo.req.LoginReqVO;

import com.yingxue.lesson.vo.req.UserAddReqVO;
import com.yingxue.lesson.vo.req.UserPageReqVO;
import com.yingxue.lesson.vo.req.userVo.UserOwnRoleReqVO;
import com.yingxue.lesson.vo.req.userVo.UserUpdateDetailInfoReqVO;
import com.yingxue.lesson.vo.req.userVo.UserUpdatePwdReqVO;
import com.yingxue.lesson.vo.req.userVo.UserUpdateReqVO;
import com.yingxue.lesson.vo.resp.LoginRespVO;
import com.yingxue.lesson.vo.resp.PageVO;
import com.yingxue.lesson.vo.resp.userVo.UserOwnRoleRespVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TokenSetting tokenSettings;
    @Autowired
    private PermissionService permissionService;

    /**
     * 用户登录
     */
    @Override
    public LoginRespVO login(LoginReqVO vo) {
//        try {
//            TimeUnit.SECONDS.sleep(5);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//            System.out.println("..............................");
//        }
        //1.通过用户名查找用户
        SysUser sysUser = sysUserMapper.selectByUsername(vo.getUsername());
        //2.对用户进行判断
        if(sysUser==null){
            throw new BusinessException(BaseResponseCode.ACCOUNT_ERROR);
        }
        if(sysUser.getStatus()==2){
            throw new BusinessException(BaseResponseCode.ACCOUNT_LOCK_TIP);
        }
        if(!PasswordUtils.matches(sysUser.getSalt(),vo.getPassword(),sysUser.getPassword())){
            throw new BusinessException(BaseResponseCode.ACCOUNT_PASSWORD_ERROR);
        }
        //3.封装用户信息(封装用户拥有的角色，拥有的权限)
        Map<String,Object> claims=new HashMap<>();
        claims.put(Constant.JWT_USER_NAME,sysUser.getUsername());
        claims.put(Constant.ROLES_INFOS_KEY,getRoleByUserId(sysUser.getId()));
        claims.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionByUserId(sysUser.getId()));
        //4.生成认证token
        String accessToken= JwtTokenUtil.getAccessToken(sysUser.getId(),claims);
        log.info("accessToken={}",accessToken);
        Map<String,Object> refreshTokenClaims=new HashMap<>();
        refreshTokenClaims.put(Constant.JWT_USER_NAME,sysUser.getUsername());
        //5.生成刷新token
        String refreshToken=null;
        if(vo.getType().equals("1")){
            refreshToken=JwtTokenUtil.getRefreshToken(sysUser.getId(),refreshTokenClaims);
        }else {
            refreshToken=JwtTokenUtil.getRefreshAppToken(sysUser.getId(),refreshTokenClaims);
        }
        log.info("refreshToken={}",refreshToken);
        LoginRespVO loginRespVO=new LoginRespVO();
        loginRespVO.setUserId(sysUser.getId());
        loginRespVO.setRefreshToken(refreshToken);
        loginRespVO.setAccessToken(accessToken);
        return loginRespVO;
    }

    /**
     * 用过 userId 查询 用户的角色信息
     */
    private List<String> getRoleByUserId(String userId){
        List<String> roleName = roleService.getRoleNameByUserId(userId);
        return roleName;

    }

    /**
     * 通过 userId 查询 用户的权限信息
     */
    private List<String> getPermissionByUserId(String userId){
        List<String> permission = permissionService.getPermissionByUserId(userId);
        return permission;
    }

    /**
     * 查询所有用户
     */
    @Override
    public PageVO<SysUser> pageInfo(UserPageReqVO vo) {
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<SysUser> sysUsers = sysUserMapper.selectAll(vo);
        //设置用户所属部门名
        for (SysUser sysUser : sysUsers) {
            SysDept sysDept = sysDeptMapper.selectByPrimaryKey(sysUser.getDeptId());
            if(sysDept!=null){
                sysUser.setDeptName(sysDept.getName());
            }
        }
        return PageUtil.getPageVo(sysUsers);
    }

    /**
     *添加用户
     */
    @Override
    public void addUser(UserAddReqVO vo) {
        SysUser sysUser=new SysUser();
        BeanUtils.copyProperties(vo,sysUser);
        sysUser.setId(UUID.randomUUID().toString());
        sysUser.setCreateTime(new Date());
        String salt=PasswordUtils.getSalt();
        String ecdPwd=PasswordUtils.encode(vo.getPassword(),salt);
        sysUser.setSalt(salt);
        sysUser.setPassword(ecdPwd);
        int i = sysUserMapper.insertSelective(sysUser);
        if(i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
    }


    /**
     * 根据用户id获取用户拥有角色
     */
    @Override
    public UserOwnRoleRespVO getUserOwnRole(String userId) {
        UserOwnRoleRespVO vo = new UserOwnRoleRespVO();
        vo.setOwnRoles(userRoleService.getRoleIdsByUserId(userId));
        vo.setAllRole(roleService.selectAll());
        return vo;
    }

    /**
     * 添加用户角色
     */
    @Override
    public void addUserOwnRole(UserOwnRoleReqVO vo) {
        userRoleService.addUserRoleInfo(vo);
        //标记用户 要主动去刷新
        redisService.set(Constant.JWT_REFRESH_KEY + vo.getUserId(), vo.getUserId(), tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);

    }

    /**
     * 刷新token
     */
    @Override
    public String refreshToken(String refreshToken) {
        //1.判断它是否过期
        //2.判断它是否被加如了黑名
        if(!JwtTokenUtil.validateToken(refreshToken) || redisService.hasKey(Constant.JWT_REFRESH_TOKEN_BLACKLIST+refreshToken)){
            throw new BusinessException(BaseResponseCode.TOKEN_ERROR);
        }
        String userId = JwtTokenUtil.getUserId(refreshToken);
        String username = JwtTokenUtil.getUserName(refreshToken);
        HashMap<String, Object> map = new HashMap<>();
//        map.put(Constant.JWT_REFRESH_KEY,getPermissionByUserId(userId));
//        map.put(Constant.ROLES_INFOS_KEY,getRoleByUserId(userId));
//        map.put(Constant.JWT_REFRESH_KEY,username);
        map.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionByUserId(userId));
        map.put(Constant.ROLES_INFOS_KEY,getRoleByUserId(userId));
        map.put(Constant.JWT_USER_NAME,username);
        String newRefreshToken = JwtTokenUtil.getRefreshToken(userId, map);

        return newRefreshToken;
    }

    /**
     * 更新用户
     */
    @Override
    public void updateUserInfo(UserUpdateReqVO vo, String operationId) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(vo,sysUser);
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateId(operationId);

        if (StringUtils.isEmpty(vo.getPassword())){
            sysUser.setPassword(null);
        }else {
            String salt = PasswordUtils.getSalt();
            String endPwd = PasswordUtils.encode(vo.getPassword(), salt);
            sysUser.setSalt(salt);
            sysUser.setPassword(endPwd);
        }

        int i = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        if (i != 1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //状态锁定，标记redis 锁定
        if(vo.getStatus()==2){
            redisService.set(Constant.ACCOUNT_LOCK_KEY+vo.getId(),vo.getId());
        }else {
            redisService.delete(Constant.ACCOUNT_LOCK_KEY+vo.getId());
        }
    }


    /**
     * 批量/删除用户
     */
    @Override
    public void deletedUsers(List<String> list, String operationId) {
        SysUser sysUser = new SysUser();
        sysUser.setUpdateId(operationId);
        sysUser.setUpdateTime(new Date());
        int i = sysUserMapper.deletedUsers(sysUser, list);
        if (i==0){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        for (String userId: list) {
            redisService.set(Constant.DELETED_USER_KEY+userId,userId,tokenSettings.getRefreshTokenExpireTime().toMillis(),TimeUnit.MINUTES);
            //清楚用户授权数据缓存
            redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
        }

    }


    /**
     * 退出登录
     */
    @Override
    public void logout(String accessToken, String refreshToken) {
        //1.判断token是否为空
        if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)){
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        //2.shiro主体提交退出
        Subject subject = SecurityUtils.getSubject();
        if (subject != null){
            subject.logout();
        }

        String userId = JwtTokenUtil.getUserId(accessToken);
        //3.标记退出用户的token

        //把accessToken 加入黑名单
        redisService.set(Constant.JWT_ACCESS_TOKEN_BLACKLIST+accessToken,userId,JwtTokenUtil.getRemainingTime(accessToken),TimeUnit.MILLISECONDS);
        //把refreshToken 加入黑名单
        redisService.set(Constant.JWT_REFRESH_TOKEN_BLACKLIST+refreshToken,userId,JwtTokenUtil.getRemainingTime(accessToken),TimeUnit.MILLISECONDS);
    }


    /**
     * 编辑个人信息 --获取个人信息
     */
    @Override
    public SysUser detailUserInfo(String userId) {
        return sysUserMapper.selectByPrimaryKey(userId);
    }

    /**
     * 个人用户编辑信息接口
     */
    @Override
    public void userUpdateDetailInfo(UserUpdateDetailInfoReqVO vo, String userId) {
        //1.封装用户数据
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(vo,sysUser);
        sysUser.setUpdateTime(new Date());
        sysUser.setId(userId);
        sysUser.setUpdateId(userId);
        //2.更新
        int i = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
    }

    /**
     * 修改个人密码
     */
    @Override
    public void updateUserPwd(UserUpdatePwdReqVO vo, String accessToken, String refreshToken) {
        String userId = JwtTokenUtil.getUserId(accessToken);
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
        if (sysUser==null){
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        //1.验证旧密码是否正确
        if (!PasswordUtils.matches(sysUser.getSalt(),vo.getOldPwd(),sysUser.getPassword())){
            throw new BusinessException(BaseResponseCode.OLD_PASSWORD_ERROR);
        }
        //2.更新密码
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateId(userId);
        sysUser.setPassword(PasswordUtils.encode(vo.getNewPwd(),sysUser.getSalt()));
        int i = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //3.标记用户 token 刷新token

        //把token 加入黑名单 禁止再访问我们的系统资源
        redisService.set(Constant.JWT_ACCESS_TOKEN_BLACKLIST+accessToken,userId,JwtTokenUtil.getRemainingTime(accessToken), TimeUnit.MILLISECONDS);
        //把 refreshToken 加入黑名单 禁止再拿来刷新token
        redisService.set(Constant.JWT_REFRESH_TOKEN_BLACKLIST+refreshToken,userId,JwtTokenUtil.getRemainingTime(refreshToken),TimeUnit.MILLISECONDS);


    }
}
